local skynet = require "skynet"
local queue = require "skynet.queue"
local snax = require "snax"
local CMD = require "center_proto"
local sharedata = require "sharedata"
local cluster = require "cluster"
require "skynet.manager"

local table_db = {}
local user_db = {}
local mail_msg = {}
local first_gate = 0
local DataSer = {}
local proxy = nil 
-- 游戏服务器集合信息
local GameServer = {tableobj={}}


--用户表管理进程
local function manage_user_db()
    while true do
        local now_time=skynet.time()
        local user_num=0
        for k,v in pairs(user_db) do
            user_num=user_num+1
            if now_time-v.lasttime>24*3600 and v.status == 0 then --超过24小时断线的用户被清理
                user_db[k]=nil
                skynet.error("[centerser] manage_user_db timer user has clear user_id: ",k)
                user_num=user_num-1
            end
        end
        skynet.error("[centerser] manage_user_db user db length is: ",user_num)
        skynet.sleep(6000)
    end
end

--桌子表管理进程
local function manage_table_db()
    while true do
        local now_time=skynet.time()
        local table_num=0
        for k,v in pairs(table_db) do
            table_num=table_num+1
            if now_time-v.lasttime>2*3600 then --超过2小时未解散的用户强行解散，用户对应桌子置0
                for key,vaule in pairs(v.user) do   
                    user_db[vaule].table_id=0
                    skynet.error("[centerser] manage_table_db timer table has dismiss table_id: " ,k," user_id: ",vaule)
                end
                table_db[k]=nil
                table_num=table_num-1
            end
        end
        skynet.error("[centerser] manage_table_db table db length is: ",table_num)
        skynet.sleep(6000)
    end
end


local function query_msg(user_id)
    skynet.error("[centerser] query_msg rev auth request user_id: ",user_id)
    local user=user_db[user_id]
    if user then
        skynet.error("[centerser] query_msg user 在线 user_id:"..user_id.." tableid:"..user.table_id)
        user.status=1
        return {table_id = user.table_id, is_match = user.is_match }
    else
        skynet.error("[centerser] query_msg user 不在线 user_id:",user_id)
        user_db[user_id]={status=1,lasttime=skynet.time(),table_id=0,is_match=0}
        return {table_id = 0, is_match = 0 }
    end
    
end

--更新用户信息，status 0：断线 1：上线
local function update_user(user_id)
    skynet.error("[centerser] update_user rev disconnect request user_id: ",user_id)
    local user=user_db[user_id]
    if user then
        user.status=0
        user.lasttime=skynet.time()
    end
end


local function update_usertable(user_id)
    skynet.error("[centerser] update_usertable 客户端主动清理用户桌子: ",user_id)
    local user=user_db[user_id]
    if user then
        user.table_id=0
    end
    return {mcmd = CMD.Main_Center_module, scmd = CMD.Sub_CenterToModule_ClearTableId, msg=nil}
end

local function update_usermatch(user_id)

    skynet.error("[centerser] update_usermatch 客户端主动清理用户比赛状态: ",user_id)
    local user=user_db[user_id]
    if user then
        user.is_match=0
    end
    return {mcmd = CMD.Main_Center_module, scmd = CMD.Sub_CenterToModule_ClearMatch, msg=nil}
end

function DataSer.update_user_state(user_id, state) --state 0: 正常游戏 1：报名参加比赛

    skynet.error("[centerser] update_user_state : ",user_id,state)
    local user=user_db[user_id]
    if user then
        user.is_match = state
    end
end

local function create_table_msg(sz,msg)   
  
    local table_id,user_id,is_agent=string.unpack("I4I4I4", msg, 5)
    skynet.error("[centerser] create_table_msg table  has create user_id: ",user_id," table_id: ",table_id," is_agent: ",is_agent)
    if is_agent == 0 then 
        table_db[table_id]={user={user_id},lasttime=skynet.time()}
        user_db[user_id].lasttime=skynet.time()
        user_db[user_id].table_id=table_id    
    elseif is_agent == 1 then
        table_db[table_id]={user={},lasttime=skynet.time()}
    end
end   

local function update_table(sz,msg)

    local table_id,status,user_num=string.unpack("I4I1I1", msg, 5)
    local user={}
    local flag=0
    for i=1,user_num do
       local user_id=string.unpack("I4",msg,11+flag)
       table.insert(user,user_id)
       flag=flag+4
    end
    
    if not table_db[table_id] then
        return
    end
    
    if status==0 then     --桌子解散
        skynet.error("[centerser] update_table table has dismiss table_id: " ,table_id)
        for k,v in pairs(user) do
            if user_db[v] then 
                user_db[v].table_id=0
                skynet.error("[centerser] update_table table has dismiss table_id: " ,table_id," user_id: ",v)
            end
        end
        table_db[table_id]=nil
              
    elseif status==1 then --游戏开始，更新桌子信息
        table_db[table_id].user=user
        table_db[table_id].lasttime=skynet.time()
        for k,v in pairs(user) do
            if user_db[v] then 
                user_db[v].table_id=table_id
                skynet.error("[centerser] update_table game start table update user table_id : " ,table_id," user_id: ",v)
            end
        end
              
    elseif status==2 then --有人进入，更新桌子信息
        for k,v in pairs(user) do
            if user_db[v] then 
                user_db[v].table_id=table_id
                table.insert(table_db[table_id].user,v)
                skynet.error("[centerser] update_table user enter table  table_id: ",table_id," user_id: ",v)
            end
        end
        
    elseif status==3 then --有人退出，更新桌子信息
        for k,v in pairs(user) do
            if user_db[v] then 
                user_db[v].table_id=0
                for key,vaule in pairs(table_db[table_id].user) do
                    if vaule==v then
                       table_db[table_id].user[key]=nil
                       skynet.error("[centerser] update_table user out table  table_id : ",table_id," user_id: ",v)
                    end
                end
            end
        end
    end
end

-- 游戏服注册
local function GameServerReg(msg,addr)
    
    local gameid,tid,ttype = string.unpack("<I4HH", msg, 5)
    
    skynet.error("[centerser] GameServerReg GID="..gameid.." TID="..tid.." Type="..ttype.." addr="..addr)
    skynet.send(addr,"lua","set_tableid",{gid =gameid,tblid=tid,ttype=ttype})

    if GameServer[ttype] == nil then
        GameServer[ttype] = {}
    end

    if GameServer[ttype][gameid] == nil then
        GameServer[ttype][gameid] = {}
    end

    GameServer[ttype][gameid][tid] = addr
    GameServer.tableobj[tid] = addr
    
    cluster.send("center", proxyser,"UpdateGameServer",GameServer)
    sharedata.update("GameServerShareObj", GameServer)

    skynet.error("[centerser] GameServerReg ---------------GameServer----------------")
    
    for ttype , tobj in pairs(GameServer) do
        if type(ttype)=="number" then
            for gameid,gobj in pairs(tobj) do
                for tblid,addr in pairs(gobj) do
                    skynet.error("[centerser] GameServerReg in game_server type="..ttype.." gameid="..gameid.." tableid="..tblid.." addr="..addr)
                end
            end
        end
    end
    
    skynet.error("[centerser] GameServerReg ---------------GameServer.tableobj----------------")

    for k,td in pairs(GameServer.tableobj) do
        skynet.error("[centerser] in table_server table id="..k.." addr="..td)
    end
    skynet.error("[centerser] GameServerReg ---------------END----------------")
end

-- 游戏服注销
local function GameServerUnReg(msg,addr)
    
    skynet.error("[centerser] gameid=",msg.gid," type=",msg.type," tableid=",msg.tid," addr=",addr)

    GameServer[msg.type][msg.gid][msg.tid] = nil

    for k ,v in pairs(GameServer.tableobj) do
        if k == msg.tid then
            GameServer.tableobj[k] = nil
        end
        skynet.error("[centerser] GameServerUnReg k="..k)        
    end

    sharedata.update("GameServerShareObj", GameServer)
    cluster.send("center", proxyser,"UpdateGameServer",GameServer)
    skynet.error("[centerser] GameServerUnReg ============GameServer============")

    for ttype , tobj in pairs(GameServer) do
        if type(ttype)=="number" then
            for gameid,gobj in pairs(tobj) do
                for tblid,addr in pairs(gobj) do
                    skynet.error("[centerser] in game_server type="..ttype.." gameid="..gameid.." tableid="..tblid.." addr="..addr)
                end
            end
        end
    end

    skynet.error("[centerser] GameServerUnReg ============GameServer.tableobj============")

    for k,td in pairs(GameServer.tableobj) do
        skynet.error("[centerser] in table_server table id="..k.." addr="..td)
    end

    skynet.error("[centerser] GameServerUnReg ============END============")
end


-- 网关服务器启动
function DataSer.request_registGate()
    first_gate = first_gate + 1
    mail_msg[tostring(first_gate)] = {}
    skynet.error("[centerser] DataSer.request_registGate = "..first_gate)
    return first_gate
end


-- 取得网关相关的消息，并删除去消息
function DataSer.request_getGateMail(gateid)

    --skynet.error("DataSer.request_getGateMail = "..gateid)
    if mail_msg[tostring(gateid)] ~= nil then
        local ret = mail_msg[tostring(gateid)]
        mail_msg[tostring(gateid)] = {}
        return ret
    end
    return nil
end

-- 发送消息到消息槽里,　注意这个消息是不返回的
function DataSer.send_GateMail(playid, mcmd, scmd, msg)
    if user_db[playid] == nil then
        skynet.error("[centerser] accept.send_GateMail playid error find error id:"..playid)
        return
    end

    local gateid = user_db[playid].gateid
    if gateid == nil then
        skynet.error("[centerser] accept.send_GateMail gateid error find error id:"..playid)
        return
    end

    local agentid = user_db[playid].agentid

    if mail_msg[tostring(gateid)] == nil then
        mail_msg[tostring(gateid)] = {}
    end

    table.insert(mail_msg[tostring(gateid)], {playid = playid , agentid = agentid, mcmd = mcmd, scmd = scmd, msg = msg})

    skynet.error("[centerser] accept.send_GateMail "..gateid.."  playid="..playid)
end

-- 发送消息到多个用户, pkayidarr 是一个用户id表
function DataSer.send_mult_GateMail(playidarr, mcmd, scmd, msg)
   for k, v in ipairs(playidarr) do
        DataSer.send_GateMail(v, mcmd, scmd, msg)
    end
end

--[[
    1: 广播消息    gameid = nil        2000          msg
    2: 游戏广播    gameid = XXX        2001          游戏
                                       2002          大厅
--]]

function DataSer.send_BoradMsg(gameid, istable, msg)
    for k, v in pairs(mail_msg) do
        --skynet.error("accept.send_BoradMsg ", gameid, istable, msg)
        if type(v) == "table" then
            table.insert(v, {gameid=gameid, istable=istable, msg = msg})
        end
    end
end

-- 发送消息到消息槽里
function DataSer.regToCent(conf)
    local playid = conf.playerid
    local gateid = conf.gateid
    local agentid = conf.agentid

    skynet.error("[centerser] accept.regToCent "..gateid.." agentid "..agentid)

    if user_db[playid] ~= nil then
        user_db[playid].gateid = gateid
        user_db[playid].agentid = agentid
    else
        user_db[playid] = {};
        user_db[playid].gateid = gateid
        user_db[playid].agentid = agentid
    end
end


function DataSer.request_module(scmd,sz,msg,addr) --scmd,sz,msg,addr
    skynet.error("[centerser] request_module game scmd,sz,msg,addr : ",scmd,sz,msg,addr)
    if scmd==CMD.Sub_ModuleToCenter_CreateTable then 
        create_table_msg(sz, msg)
    elseif scmd==CMD.Sub_ModuleToCenter_UpdateTable then 
        update_table(sz, msg)
    elseif scmd==CMD.Sub_ModuleToCenter_GSReg then
        GameServerReg(msg, addr)
    elseif scmd==CMD.Sub_ModuleToCenter_GSUnReg then
        GameServerUnReg(msg, addr)
    end
end

function DataSer.request_gate(conf)

	if conf.cmd==CMD.Sub_ModuleToCenter_Query then       
        return  query_msg(conf.playid)
    elseif conf.cmd==CMD.Sub_ModuleToCenter_UserDisn then 
        update_user(conf.playid)
    elseif conf.cmd==CMD.Sub_ModuleToCenter_ClearTableReq then
        return update_usertable(conf.playid)
    elseif conf.cmd==CMD.Sub_ModuleToCenter_ClearMatchReq then
        return update_usermatch(conf.playid)
    end

	return nil
end

function DataSer.get_gameServerObj()
    
    skynet.error("[centerser] proxyser get data")
    return  GameServer 
end

-- function response.error()
	-- error "throw an error"
-- end



function DataSer.start( ... )
	skynet.error("[centerser] server start:", ...)
	--snax.enablecluster()
    skynet.fork(manage_user_db)
    skynet.fork(manage_table_db)

    sharedata.new("GameServerShareObj", GameServer)
    proxyser = cluster.query("center", "proxyser")
end

skynet.start(function()
	skynet.dispatch("lua", function(_,_, command, ...)
		local f = DataSer[command]
		skynet.ret(skynet.pack(f(...)))
	end)
    
    math.randomseed(os.time())
end)

function exit(...)
	skynet.error ("[centerser] server exit:", ...)
end
